const express = require('express')
const path = require('path')
const cors = require('cors')
const bodyParser = require('body-parser')
const multiparty = require('multiparty')
const fes = require('fs-extra')
const app = express()
const port = 3000
app.use(cors())
app.use(bodyParser.json())

// 上传文件
app.post('/upload', async (req, res) => {
  const form = new multiparty.Form()
  const BASE_URL = path.resolve(__dirname, 'uploads') // 文件保存的根目录
  form.parse(req, async (err, fields, files) => {
    // 上传失败
    if (err) {
      res.status(500).json({
        ok: false,
        message: err.message
      })
    }
    // 上传成功
    const fileHash = fields.fileHash[0]
    const chunkHash = fields.chunkHash[0]
    // 1. 利用上传过来的文件hash去创建文件夹 没有就创建 有就跳过
    const chunkPath = path.resolve(BASE_URL, fileHash)
    if (!fes.existsSync(chunkPath)) {
      await fes.mkdir(chunkPath)
    }
    // 2. 将文件移动到文件夹中
    const oldPath = files.chunk[0].path
    await fes.move(oldPath, path.resolve(chunkPath, chunkHash))
    res.status(200).json({
      ok: true,
      message: '上传成功'
    })
  })
})

// 截取文件后缀
function getSuffix(fileName) {
  return fileName.split('.').pop()
}

// 合并文件
app.post('/merge', async (req, res) => {
  const { fileHash, fileName, size } = req.body // 获得参数
  console.log(fileHash, fileName, size)

  const BASE_URL = path.resolve(__dirname, 'uploads') // 文件保存的根目录
  const filePathName = fileHash + '.' + getSuffix(fileName) // 文件名

  // 判断文件是否存在 存在则不需要合并
  if (fes.existsSync(path.resolve(BASE_URL, filePathName))) {
    res.status(200).json({
      ok: true,
      message: '文件已存在'
    })
  }

  // 判断存放文件切片的文件是否存在
  const chunkPath = path.resolve(BASE_URL, fileHash)
  if (!fes.existsSync(chunkPath)) {
    res.status(500).json({
      ok: false,
      message: '文件不存在'
    })
  }

  // 合并文件
  const chunkFiles = fes.readdirSync(chunkPath)

  // 1. 对文件进行排序
  chunkFiles.sort((a, b) => a.split('-')[1] - b.split('-')[1])

  // console.log(chunkFiles)

  // 2. 创建读取流
  const list = chunkFiles.map((chunkName, index) => {
    return new Promise((resolve, reject) => {
      const fileChunkPath = path.resolve(chunkPath, chunkName)
      const readStream = fes.createReadStream(fileChunkPath)
      // 3. 创建写入流
      const writeStream = fes.createWriteStream(
        path.resolve(BASE_URL, filePathName),
        {
          start: index * size, // 指定写入位置
          end: (index + 1) * size // 指定写入位置
        }
      )
      // 4. 将读取流中的数据写入到写入流中
      readStream.pipe(writeStream)

      // 5. 监听写入流写入完成事件
      writeStream.on('finish', () => {
        fes.unlink(fileChunkPath)
        resolve()
      })
    })
  })

  await Promise.all(list)
  // 删除文件夹
  await fes.remove(chunkPath)
  // 合并成功
  res.status(200).json({
    ok: true,
    message: '合并成功'
  })
})

// 查询当前文件是否已经上传从而实现妙传的效果
app.post('/check', async (req, res) => {
  const { fileHash, fileName } = req.body // 获得参数

  const BASE_URL = path.resolve(__dirname, 'uploads') // 文件保存的根目录

  const filePathName = fileHash + '.' + getSuffix(fileName) // 文件名

  const isExist = fes.existsSync(path.resolve(BASE_URL, filePathName)) // 判断文件是否存在
  res.status(200).json({
    ok: true,
    isExist,
  })
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
